package com.dynabook.ems.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dynabook.ems.common.BaseResponse;
import com.dynabook.ems.common.ErrorCode;
import com.dynabook.ems.common.ResultUtils;
import com.dynabook.ems.constant.MailTemplate;
import com.dynabook.ems.constant.SampleConstant;
import com.dynabook.ems.disruptor.BorrowUpdate.BorrowUpdateDisruptorProducer;
import com.dynabook.ems.exception.BusinessException;
import com.dynabook.ems.mapper.EmsEngineWorkOrderMapper;
import com.dynabook.ems.mapper.EmsMyBorrowMapper;
import com.dynabook.ems.mapper.EmsWorkOrderDetailMapper;
import com.dynabook.ems.model.dto.MyBorrowedSampleListRequest;
import com.dynabook.ems.model.dto.ReturnMachineListDTO;
import com.dynabook.ems.model.dto.WorkOrderSampleApprovalListRequest;
import com.dynabook.ems.model.dto.WorkOrderSampleBatchApprovalRequest;
import com.dynabook.ems.model.entity.*;
import com.dynabook.ems.model.enums.DetailStatusEnum;
import com.dynabook.ems.model.enums.MailEnum;
import com.dynabook.ems.model.enums.ModelStatusEnum;
import com.dynabook.ems.model.enums.RedisKeyEnum;
import com.dynabook.ems.model.vo.*;
import com.dynabook.ems.service.*;
import com.dynabook.ems.utils.SampleStatusUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
* @author tester
* @description 针对表【ems_my_borrow】的数据库操作Service实现
* @createDate 2025-07-01 13:58:28
*/
@Service
@Slf4j
public class EmsMyBorrowServiceImpl extends ServiceImpl<EmsMyBorrowMapper, EmsMyBorrow>
    implements EmsMyBorrowService {

    @Resource
    private EmsBorrowHistoryService emsBorrowHistoryService;
    
    @Resource
    private BorrowUpdateDisruptorProducer borrowUpdateDisruptorProducer;
    
    @Resource
    private EmsEngineWorkOrderService emsEngineWorkOrderService;
    
    @Resource
    private EmsLogRecordService emsLogRecordService;
    
  
    
    @Resource
    private EmsMainEngineService emsMainEngineService;
    
    @Resource
    private EmsEngineWorkOrderMapper emsEngineWorkOrderMapper;
    
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    
    @Resource
    private WorkOrderStatusSyncService workOrderStatusSyncService;
    
    @Resource
    private SampleStatusUtils sampleStatusUtils;
    @Resource
    private EmsWorkOrderDetailMapper emsWorkOrderDetailMapper;

    @Resource
    private MailTemplate mailTemplate;
    @Autowired
    private UsersService usersService;
    @Autowired
    private EmsMailQueueService emsMailQueueService;

    @Override
    public EmsMyBorrowVO getCurrentUseList(String fixedNo) {
        try {
            if (fixedNo == null || fixedNo.trim().isEmpty()) {
                throw new IllegalArgumentException("fixedNo不能为空");
            }

            QueryWrapper<EmsMyBorrow> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("fixed_no", fixedNo);
            List<EmsMyBorrow> list = this.list(queryWrapper);

            EmsMyBorrowVO emsMyBorrowVO = new EmsMyBorrowVO();
            emsMyBorrowVO.setEmsCurrentUse(list != null ? list : new ArrayList<>());
            emsMyBorrowVO.setTotalNum(list != null ? list.size() : 0);
            return emsMyBorrowVO;
        } catch (Exception e) {
            log.error("查询当前使用列表失败，fixedNo: {}", fixedNo, e.getMessage());
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "查询当前使用列表失败");
        }
    }

    @Override
    public Boolean updateOldData() {
        try {
            // 分页查询，避免一次性加载10万数据到内存
            int pageSize = 1000; // 每批处理1000条
            int pageNum = 1;
            
            while (true) {
                // 使用分页查询
                Page<EmsBorrowHistory> page = new Page<>(pageNum, pageSize);
                Page<EmsBorrowHistory> result = emsBorrowHistoryService.page(page);
                
                if (result.getRecords().isEmpty()) {
                    break; // 没有更多数据了
                }


                // 将数据推送到disruptor进行异步处理
                borrowUpdateDisruptorProducer.pushBorrowHistoryBatch(result.getRecords());
                
                log.info("已推送第{}页数据到异步处理队列，数量: {}", pageNum, result.getRecords().size());
                
                pageNum++;
                
                // 如果当前页数据少于pageSize，说明是最后一页
                if (result.getRecords().size() < pageSize) {
                    break;
                }
            }
            
            log.info("所有数据已推送到异步处理队列，总页数: {}", pageNum - 1);

            return true;
            
        } catch (Exception e) {
            log.error("推送数据到异步处理队列失败", e);
            return false;
        }
    }

    @Override
    public Page<ReturnMachineListVO> getMachineList(ReturnMachineListDTO returnMachineListDTO) {
        try {
            Page<ReturnMachineListVO> page = new Page<>(returnMachineListDTO.getCurrent(), returnMachineListDTO.getPageSize());
            return this.baseMapper.getMachineList(page, returnMachineListDTO);
        }catch (Exception e) {
            log.error("查询当前使用列表失败，getMachineList: {}", returnMachineListDTO, e.getMessage());
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "查询当前使用列表失败");
        }
    }

    @Override
    public Page<SampleListVO> getMyBorrowedSampleList(MyBorrowedSampleListRequest request, String userId) {
        log.info("获取用户已借样品列表，用户ID: {}, 工单号: {}, 请求参数: {}", 
                userId, request.getWorkOrderNumber(), request);
        
        if (StrUtil.isBlank(userId)) {
            log.error("用户ID为空，无法查询");
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户ID不能为空");
        }
        
        // 1. 先查询当前工单下已绑定的样品列表
        Set<String> selectedFixedNos = new HashSet<>();
        if (StrUtil.isNotBlank(request.getWorkOrderNumber())) {
            try {
                LambdaQueryWrapper<EmsEngineWorkOrder> workOrderWrapper = new LambdaQueryWrapper<>();
                workOrderWrapper.eq(EmsEngineWorkOrder::getWorkOrderNumber, request.getWorkOrderNumber())
                               .eq(EmsEngineWorkOrder::getIsDelete, 0);
                List<EmsEngineWorkOrder> workOrderList = emsEngineWorkOrderService.list(workOrderWrapper);
                
                selectedFixedNos = workOrderList.stream()
                        .map(EmsEngineWorkOrder::getFixedNo)
                        .collect(Collectors.toSet());
                
                log.info("工单 {} 已绑定样品数量: {}", request.getWorkOrderNumber(), selectedFixedNos.size());
            } catch (Exception e) {
                log.warn("查询工单绑定样品失败，继续执行用户已借样品列表查询: {}", e.getMessage());
            }
        }
        
        // 2. 创建分页对象
        Page<SampleListVO> page = new Page<>(request.getCurrent(), request.getPageSize());
        
        // 3. 执行查询
        Page<SampleListVO> result = this.baseMapper.pageMyBorrowedSampleList(page, userId, request.getSearchText(),request.getType());
        
        // 4. 设置is_select字段
        if (result.getRecords() != null && !result.getRecords().isEmpty()) {
            for (SampleListVO sample : result.getRecords()) {
                if (selectedFixedNos.contains(sample.getFixedNo())) {
                    sample.setIs_select(1); // 已选择
                } else {
                    sample.setIs_select(0); // 未选择
                }
            }
        }
        
        log.info("获取用户已借样品列表完成，用户ID: {}, 总记录数: {}, 总页数: {}, 已选择样品数: {}", 
                userId, result.getTotal(), result.getPages(), selectedFixedNos.size());
        return result;
    }

    @Override
    public Page<WorkOrderSampleApprovalListVO> getWorkOrderSampleApprovalList(WorkOrderSampleApprovalListRequest request) {
        log.info("查询样机工单待审批列表，参数: {}", request);
        
        try {
            // 参数校验
            if (request == null) {
                request = new WorkOrderSampleApprovalListRequest();
            }
            
            // 设置默认排序
            if (StrUtil.isBlank(request.getSortField())) {
                request.setSortField("borrow_time");
                request.setSortOrder("desc");
            }
            
            // 创建分页对象
            Page<WorkOrderSampleApprovalListVO> page = new Page<>(request.getCurrent(), request.getPageSize());
            
            // 执行分页查询
            Page<WorkOrderSampleApprovalListVO> result = this.baseMapper.pageWorkOrderSampleApprovalList(page, request);
            
            log.info("查询样机工单待审批列表完成，总记录数: {}, 总页数: {}", result.getTotal(), result.getPages());
            return result;
            
        } catch (Exception e) {
            log.error("查询样机工单待审批列表失败: {}", e.getMessage(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "查询样机工单待审批列表失败");
        }
    }



    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResponse<Boolean> batchSampleApproval(WorkOrderSampleBatchApprovalRequest request, HttpServletRequest httpServletRequest) {
        log.info("批量样机审批开始，参数: {}", request);
        
        try {
            // 1. 参数验证
            if (request == null || request.getEmsRequestIds() == null || request.getEmsRequestIds().isEmpty()) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求参数不能为空");
            }
            
            if (!"agree".equals(request.getAction()) && !"reject".equals(request.getAction())) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "操作类型只能是agree或reject");
            }
            
            // 2. 获取用户信息
            UserLoginVO userLoginVO = (UserLoginVO) httpServletRequest.getSession().getAttribute("user_login");
            if (userLoginVO == null) {
                throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR, "用户未登录");
            }
            
            // 3. 查询待审批的借用记录
            List<String> requestIds = request.getEmsRequestIds();
            List<EmsMyBorrow> borrowList = this.listByIds(requestIds);
            if (borrowList.isEmpty()) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "未找到对应的借用记录");
            }
            
            // 4. 根据操作类型执行不同逻辑
            if ("agree".equals(request.getAction())) {
                return handleApproval(borrowList, request.getRejectReason(), userLoginVO);
            } else {
                return handleRejection(borrowList, request.getRejectReason(), userLoginVO);
            }
            
        } catch (BusinessException e) {
            log.error("批量样机审批业务异常: {}", e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("批量样机审批系统异常", e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "批量样机审批失败: " + e.getMessage());
        }
    }
    
    /**
     * 处理课长同意审批逻辑（第一级审批）
     */
    private BaseResponse<Boolean> handleApproval(List<EmsMyBorrow> borrowList, String remark, UserLoginVO userLoginVO) {
        log.info("开始处理课长同意审批，记录数: {}", borrowList.size());
        
        try {
            ArrayList<HashMap<String, String>> tableDatas = new ArrayList<>();
            for (EmsMyBorrow borrow : borrowList) {
                // 1.1 修改ems_my_borrow表中的request_status为APPROVED（课长审批通过，等待样品管理员审批）
                borrow.setRequestStatus(ModelStatusEnum.WORK_ORDER_ASSIGNED.getValue());
                borrow.setUpdateTime(LocalDateTime.now());
                this.updateById(borrow);
                // 1.2 记录审批日志
                EmsLogRecord logRecord = new EmsLogRecord();
                logRecord.setFixedNo(borrow.getFixedNo());
                logRecord.setDesc("样品审批(工单)");
                logRecord.setRole(userLoginVO.getNotes());
                logRecord.setOperator(userLoginVO.getUserName());
                logRecord.setType("审批(工单)");
                logRecord.setResult("同意");
                logRecord.setReason(remark);
                logRecord.setTime(LocalDateTime.now());
                emsLogRecordService.save(logRecord);
                //1.3 修改emsmainengine表的状态
                LambdaUpdateWrapper<EmsMainEngine> emsMainEngineLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
                emsMainEngineLambdaUpdateWrapper
                        .set(EmsMainEngine::getModelStatus,ModelStatusEnum.WORK_ORDER_ASSIGNED.getValue())
                        .set(EmsMainEngine::getApproverId,userLoginVO.getUserNum())
                        .set(EmsMainEngine::getApproverName,userLoginVO.getUserName())
                        .set(EmsMainEngine::getStartDate,LocalDateTime.now())
                        .set(EmsMainEngine::getApproveDate,LocalDateTime.now());
                emsMainEngineLambdaUpdateWrapper.eq(EmsMainEngine::getFixedNo,borrow.getFixedNo());
                emsMainEngineService.update(emsMainEngineLambdaUpdateWrapper);
//                查询emsmainengine表的相关信息
                LambdaQueryWrapper<EmsMainEngine> emsMainEngineLambdaQueryWrapper =new LambdaQueryWrapper<EmsMainEngine>();
                emsMainEngineLambdaQueryWrapper.eq(EmsMainEngine::getFixedNo,borrow.getFixedNo());
                emsMainEngineLambdaQueryWrapper.select(EmsMainEngine::getModelName,EmsMainEngine::getPredictDate,EmsMainEngine::getCategory,EmsMainEngine::getBigCategory,EmsMainEngine::getRemark);
                EmsMainEngine emsMainEngineData=emsMainEngineService.getOne(emsMainEngineLambdaQueryWrapper);

                log.info("课长同意审批完成，emsRequestId: {}, fixedNo: {}", borrow.getEmsRequestId(), borrow.getFixedNo());
                // 课长同意发送邮件
                HashMap<String, String> tableDataMap= new HashMap<String, String>();
                tableDataMap.put("id",borrow.getFixedNo());
                tableDataMap.put("name",emsMainEngineData.getModelName());
                tableDataMap.put("predictDate", String.valueOf(emsMainEngineData.getPredictDate()));
                tableDataMap.put("big_category",emsMainEngineData.getBigCategory());
                tableDataMap.put("category",emsMainEngineData.getCategory());
                tableDataMap.put("number", String.valueOf(borrow.getBorrowNum()));
                tableDataMap.put("desc",emsMainEngineData.getRemark());
                tableDatas.add(tableDataMap);
            }
            List<String> sampleMail = usersService.getSampleMail(Integer.parseInt(SampleConstant.roleId));
            EmsMailQueue emsMailQueue = new EmsMailQueue();
            emsMailQueue.setType(MailEnum.APPLY.getValue());
            emsMailQueue.setMainBody(mailTemplate.getReplyApproveBorrowApplyFromSection());
            emsMailQueue.setSubject(MailTemplate.SUBJECT_BORROW_APPLY_APPROVE_FROM_SECTION+userLoginVO.getUserName());
            emsMailQueue.setFrom(userLoginVO.getEmail());
            emsMailQueue.setTo(JSONUtil.toJsonStr(sampleMail));
            emsMailQueue.setTableData(tableDatas.toString());
            emsMailQueueService.save(emsMailQueue);
            return ResultUtils.success(true);
            
        } catch (Exception e) {
            log.error("处理课长同意审批失败", e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "处理课长同意审批失败: " + e.getMessage());
        }
    }
    
    /**
     * 处理课长拒绝审批逻辑（第一级审批）
     */
    private BaseResponse<Boolean> handleRejection(List<EmsMyBorrow> borrowList, String remark, UserLoginVO userLoginVO) {
        log.info("开始处理课长拒绝审批，记录数: {}", borrowList.size());
        
        try {

            for (EmsMyBorrow borrow : borrowList) {
                String emsRequestId = borrow.getEmsRequestId();
                String fixedNo = borrow.getFixedNo();
                Integer borrowNum = borrow.getBorrowNum();
                
                // 2.1 软删除ems_my_borrow中对应的申请记录
//                borrow.setIsDelete(1);
//                borrow.setUpdateTime(LocalDateTime.now());
                this.baseMapper.deleteById(borrow);
                
                // 2.2 根据ems_request_id关联ems_engine_work_order和ems_bom_detail表，将ems_bom_detail的detail_status改为REJECTED
                List<EmsEngineWorkOrder> engineWorkOrders = emsEngineWorkOrderMapper.selectList(
                    new LambdaQueryWrapper<EmsEngineWorkOrder>()
                        .eq(EmsEngineWorkOrder::getEmsRequestId, emsRequestId)
                        .eq(EmsEngineWorkOrder::getIsDelete, 0)
                );
                
                String workOrderNumber = null;
                for (EmsEngineWorkOrder engineWorkOrder : engineWorkOrders) {
                    workOrderNumber = engineWorkOrder.getWorkOrderNumber();
                    Long detailId = engineWorkOrder.getDetailId();
                    
                    // 更新BOM详情状态为拒绝
                    EmsWorkOrderDetail emsWorkOrderDetail = new EmsWorkOrderDetail();
                    emsWorkOrderDetail.setId(detailId);
                    emsWorkOrderDetail.setDetailStatus(DetailStatusEnum.REJECTED.getValue());
                    emsWorkOrderDetail.setUpdateTime(LocalDateTime.now());
                    emsWorkOrderDetailMapper.updateById(emsWorkOrderDetail);
//                    删除emsEngineWorkOrder 表中的记录
                    emsEngineWorkOrderMapper.delete(
                        new LambdaQueryWrapper<EmsEngineWorkOrder>()
                            .eq(EmsEngineWorkOrder::getEmsRequestId, emsRequestId)
                    );
                }
                
                // 2.3 记录审批日志
                EmsLogRecord logRecord = new EmsLogRecord();
                logRecord.setFixedNo(fixedNo);
                logRecord.setDesc("样品审批(工单)");
                logRecord.setRole(userLoginVO.getNotes());
                logRecord.setOperator(userLoginVO.getUserName());
                logRecord.setType("审批(工单)");
                logRecord.setResult("拒绝");
                logRecord.setReason(remark);
                logRecord.setTime(LocalDateTime.now());
                emsLogRecordService.save(logRecord);
                
                // 2.4 更新Redis中的样机状态
                if (workOrderNumber != null) {
                    updateRedisApprovalStatus(workOrderNumber, fixedNo, 2);
                }
                
                // 2.5 更新ems_main_engine中的库存数量
                EmsMainEngine mainEngine = emsMainEngineService.getOne(
                    new LambdaQueryWrapper<EmsMainEngine>()
                        .eq(EmsMainEngine::getFixedNo, fixedNo)
                );

                if (mainEngine != null) {
                    // 减少报废数量，增加库存数量
                    sampleStatusUtils.updateSampleQuantityAndStatus(borrowNum, fixedNo, SampleStatusUtils.OperationType.SCRAP_RESTORE.getCode(),1);
                }
                LambdaQueryWrapper<EmsMainEngine> emsMainEngineLambdaQueryWrapper =new LambdaQueryWrapper<EmsMainEngine>();
                emsMainEngineLambdaQueryWrapper.eq(EmsMainEngine::getFixedNo,borrow.getFixedNo());
                emsMainEngineLambdaQueryWrapper.select(EmsMainEngine::getModelName,EmsMainEngine::getPredictDate,EmsMainEngine::getCategory,EmsMainEngine::getBigCategory,EmsMainEngine::getRemark,EmsMainEngine::getUserName,EmsMainEngine::getUserId);
                EmsMainEngine emsMainEngineData=emsMainEngineService.getOne(emsMainEngineLambdaQueryWrapper);
                // 课长拒绝发送邮件
                log.info("课长拒绝发送邮件，emsRequestId: {}, fixedNo: {}", borrow.getEmsRequestId(), borrow.getFixedNo());
                ArrayList<HashMap<String, String>> tableDatas = new ArrayList<>();
                HashMap<String, String> tableDataMap= new HashMap<String, String>();
                tableDataMap.put("id",borrow.getFixedNo());
                tableDataMap.put("name",emsMainEngineData.getModelName());
                tableDataMap.put("rejectReason", remark);
                tableDataMap.put("big_category",emsMainEngineData.getBigCategory());
                tableDataMap.put("category",emsMainEngineData.getCategory());
                tableDataMap.put("number", String.valueOf(borrow.getBorrowNum()));
                tableDataMap.put("desc",emsMainEngineData.getRemark());
                tableDatas.add(tableDataMap);
                EmsMailQueue emsMailQueue = new EmsMailQueue();
                emsMailQueue.setType(MailEnum.REJECT.getValue());
                emsMailQueue.setMainBody(mailTemplate.getReplyRejectBorrowApplyFromSection(emsMainEngineData.getUserName()));
                emsMailQueue.setSubject(MailTemplate.SUBJECT_BORROW_APPLY_REJECT_FROM_SECTION+userLoginVO.getUserName());
                emsMailQueue.setFrom(userLoginVO.getEmail());
//                TODO 课长工单拒绝样机审批
                String email = Optional.ofNullable(usersService.getLoginUserInfo(emsMainEngineData.getUserId()))
                        .map(UserLoginVO::getEmail)
                        .orElse(null);
                ArrayList<String> emailList = new ArrayList<>();
                emailList.add(email);
                emsMailQueue.setTo(String.valueOf(emailList));
                emsMailQueue.setTableData(tableDatas.toString());
                log.info("课长拒绝审批完成，emsRequestId: {}, fixedNo: {}, borrowNum: {}", emsRequestId, fixedNo, borrowNum);
                emsMailQueueService.save(emsMailQueue);
            }

            return ResultUtils.success(true);
            
        } catch (Exception e) {
            log.error("处理课长拒绝审批失败", e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "处理课长拒绝审批失败: " + e.getMessage());
        }
    }
    
    /**
     * 更新Redis中的审批状态
     */
    private void updateRedisApprovalStatus(String workOrderNumber, String fixedNo, Integer status) {
        try {
            String redisKey = RedisKeyEnum.WORKER_ORDER_APPROVAL_PREFIX.getValue() + workOrderNumber;
            
            // 检查Redis Hash中是否存在该字段
            Boolean hasField = redisTemplate.opsForHash().hasKey(redisKey, fixedNo);
            if (hasField) {
                // 直接更新Hash中的字段值
                redisTemplate.opsForHash().put(redisKey, fixedNo, status);
                // 设置过期时间
                redisTemplate.expire(redisKey, 60, TimeUnit.DAYS);
                log.info("更新Redis审批状态成功，工单号: {}, 样机编号: {}, 状态: {}", workOrderNumber, fixedNo, status);
            } else {
                log.warn("Redis Hash中未找到对应的审批记录，工单号: {}, 样机编号: {}", workOrderNumber, fixedNo);
            }
            
        } catch (Exception e) {
            log.error("更新Redis审批状态失败，工单号: {}, 样机编号: {}, 错误: {}", workOrderNumber, fixedNo, e.getMessage(), e);
            // Redis操作失败不影响主流程，只记录日志
        }
    }

    @Override
    public Page<WorkOrderSampleApprovalListVO> getWorkOrderSampleAssignmentList(WorkOrderSampleApprovalListRequest request) {
        log.info("查询样机工单代分配类别列表，参数: {}", request);
        
        try {
            // 参数校验
            if (request == null) {
                request = new WorkOrderSampleApprovalListRequest();
            }
            
            // 设置默认排序
            if (StrUtil.isBlank(request.getSortField())) {
                request.setSortField("borrow_time");
                request.setSortOrder("desc");
            }
            
            // 创建分页对象
            Page<WorkOrderSampleApprovalListVO> page = new Page<>(request.getCurrent(), request.getPageSize());
            
            // 执行分页查询
            Page<WorkOrderSampleApprovalListVO> result = this.baseMapper.pageWorkOrderSampleAssignmentList(page, request);
            
            log.info("查询样机工单代分配类别列表完成，总记录数: {}, 总页数: {}", result.getTotal(), result.getPages());
            return result;
            
        } catch (Exception e) {
            log.error("查询样机工单代分配类别列表失败: {}", e.getMessage(), e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "查询样机工单代分配类别列表失败");
        }
    }

    /**
     * 样品管理员批量审批样机工单申请（同意或拒绝）
     * @param request 批量审批请求
     * @param httpServletRequest HTTP请求
     * @return 操作结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResponse<Boolean> sampleManagerBatchApproval(WorkOrderSampleBatchApprovalRequest request, HttpServletRequest httpServletRequest) {
        log.info("样品管理员批量审批开始，参数: {}", request);
        
        try {
            // 参数校验
            validateBatchApprovalRequest(request);
            
            // 获取用户信息
            UserLoginVO userLoginVO = getUserFromSession(httpServletRequest);
            
            // 根据操作类型处理
            if ("agree".equals(request.getAction())) {
                handleSampleManagerApproval(request, userLoginVO);
            } else if ("reject".equals(request.getAction())) {
                handleSampleManagerRejection(request, userLoginVO);
            } else {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "不支持的操作类型");
            }

            log.info("样品管理员批量审批完成，操作类型: {}, 影响记录数: {}", request.getAction(), request.getEmsRequestIds().size());
            return ResultUtils.success(true);
            
        } catch (BusinessException e) {
            log.error("样品管理员批量审批失败: {}", e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("样品管理员批量审批异常", e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "样品管理员批量审批失败");
        }
    }
    
    /**
     * 校验批量审批请求参数
     */
    private void validateBatchApprovalRequest(WorkOrderSampleBatchApprovalRequest request) {
        if (request == null || CollUtil.isEmpty(request.getEmsRequestIds()) || StrUtil.isBlank(request.getAction())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数不能为空");
        }
    }
    
    /**
     * 从会话中获取用户信息
     */
    private UserLoginVO getUserFromSession(HttpServletRequest httpServletRequest) {
        UserLoginVO userLoginVO = (UserLoginVO) httpServletRequest.getSession().getAttribute("user_login");
        if (userLoginVO == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR, "用户未登录");
        }
        return userLoginVO;
    }
    
    /**
     * 处理样品管理员同意审批
     * @param request 审批请求
     * @param userLoginVO 用户信息
     */
    private void handleSampleManagerApproval(WorkOrderSampleBatchApprovalRequest request, UserLoginVO userLoginVO) {
        try {
            List<String> requestIds = request.getEmsRequestIds();
            
            // 批量更新 ems_my_borrow 的 request_status 为 USING (3)
            updateMyBorrowStatus(requestIds, ModelStatusEnum.USING.getValue());
            
            // 获取借用记录用于后续处理
            List<EmsMyBorrow> myBorrowList = getMyBorrowList(requestIds);
            
            // 批量更新 Redis 审批状态
            updateRedisApprovalStatusBatch(requestIds, "APPROVED");
            
            // 批量处理审批日志和样品状态更新
            processBorrowApprovalBatch(myBorrowList, request, userLoginVO, true);
            
            // 批量触发状态同步检查
            triggerStatusSyncBatch(requestIds, DetailStatusEnum.APPROVED.getValue());

            log.info("样品管理员同意审批完成，影响记录数: {}", requestIds.size());
            
        } catch (Exception e) {
            log.error("处理样品管理员同意审批失败", e);
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "样品管理员同意审批失败");
        }
    }
    
    /**
     * 处理样品管理员拒绝审批
     * @param request 审批请求
     * @param userLoginVO 用户信息
     */
    private void handleSampleManagerRejection(WorkOrderSampleBatchApprovalRequest request, UserLoginVO userLoginVO) {
        try {
            List<String> requestIds = request.getEmsRequestIds();
            
            // 获取借用记录用于后续处理（在软删除之前）
            List<EmsMyBorrow> myBorrowList = getMyBorrowList(requestIds);
            
            // 批量更新工单详情状态为拒绝
            updateWorkOrderDetailStatusBatch(myBorrowList, DetailStatusEnum.REJECTED.getValue());
            
            // 批量软删除 ems_my_borrow 记录
            softDeleteMyBorrowRecords(requestIds);
            
            // 清理Redis中的申请状态缓存
            cleanupRejectedRequestsFromRedis(requestIds);
            
            // 批量处理审批日志和库存恢复
            processBorrowRejectionBatch(myBorrowList, request, userLoginVO);
            
            // 批量触发状态同步检查
            triggerStatusSyncBatch(requestIds, DetailStatusEnum.REJECTED.getValue());

            log.info("样品管理员拒绝审批完成，影响记录数: {}", requestIds.size());
            
        } catch (Exception e) {
            log.error("处理样品管理员拒绝审批失败", e);
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "样品管理员拒绝审批失败");
        }
    }
    
    /**
     * 批量更新借用记录状态
     */
    private void updateMyBorrowStatus(List<String> requestIds, Integer status) {
        LambdaUpdateWrapper<EmsMyBorrow> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(EmsMyBorrow::getEmsRequestId, requestIds)
                .set(EmsMyBorrow::getRequestStatus, status)
                .set(EmsMyBorrow::getUpdateTime, LocalDateTime.now());
        this.update(updateWrapper);
    }
    
    /**
     * 批量软删除借用记录
     */
    private void softDeleteMyBorrowRecords(List<String> requestIds) {
        LambdaUpdateWrapper<EmsMyBorrow> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(EmsMyBorrow::getEmsRequestId, requestIds)
                .set(EmsMyBorrow::getIsDelete, 1)
                .set(EmsMyBorrow::getUpdateTime, LocalDateTime.now());
        this.update(updateWrapper);
    }
    
    /**
     * 获取借用记录列表
     */
    private List<EmsMyBorrow> getMyBorrowList(List<String> requestIds) {
        LambdaQueryWrapper<EmsMyBorrow> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(EmsMyBorrow::getEmsRequestId, requestIds);
        return this.list(queryWrapper);
    }
    
    /**
     * 批量更新Redis审批状态
     */
    private void updateRedisApprovalStatusBatch(List<String> requestIds, String status) {
        for (String requestId : requestIds) {
            String redisKey = RedisKeyEnum.WORKER_ORDER_APPROVAL_PREFIX.getValue() + requestId;
            redisTemplate.opsForValue().set(redisKey, status, 60, TimeUnit.DAYS);
        }
    }
    
    /**
     * 批量更新工单详情状态
     */
    private void updateWorkOrderDetailStatusBatch(List<EmsMyBorrow> myBorrowList, Integer status) {
        for (EmsMyBorrow myBorrow : myBorrowList) {
            List<EmsEngineWorkOrder> engineWorkOrders = emsEngineWorkOrderMapper.selectList(
                new LambdaQueryWrapper<EmsEngineWorkOrder>()
                    .eq(EmsEngineWorkOrder::getEmsRequestId, myBorrow.getEmsRequestId())
                    .eq(EmsEngineWorkOrder::getIsDelete, 0)
            );
            
            for (EmsEngineWorkOrder engineWorkOrder : engineWorkOrders) {
                Long detailId = engineWorkOrder.getDetailId();
                if (detailId != null) {
                    EmsWorkOrderDetail emsWorkOrderDetail = new EmsWorkOrderDetail();
                    emsWorkOrderDetail.setId(detailId);
                    emsWorkOrderDetail.setDetailStatus(status);
                    emsWorkOrderDetail.setUpdateTime(LocalDateTime.now());
                    emsWorkOrderDetailMapper.updateById(emsWorkOrderDetail);
                }
            }
        }
    }
    
    /**
     * 批量处理借用审批通过的业务逻辑
     */
    private void processBorrowApprovalBatch(List<EmsMyBorrow> myBorrowList, WorkOrderSampleBatchApprovalRequest request, 
                                          UserLoginVO userLoginVO, boolean isApproval) {
        // 批量查询主引擎数据
        Set<String> fixedNos = myBorrowList.stream().map(EmsMyBorrow::getFixedNo).collect(Collectors.toSet());
        Map<String, EmsMainEngine> mainEngineMap = getMainEngineMap(fixedNos);
        
        for (EmsMyBorrow myBorrow : myBorrowList) {
            // 记录审批日志
            saveApprovalLog(myBorrow, userLoginVO, isApproval ? "同意" : "拒绝", 
                          request.getRejectReason(), "样品分配(工单)");
            
            // 更新样品数量和状态
            if (isApproval) {
                sampleStatusUtils.updateSampleQuantityAndStatus(myBorrow.getBorrowNum(), 
                                                              myBorrow.getFixedNo(), 
                                                              SampleStatusUtils.OperationType.SCRAP.getCode(), 3);
            }
            
            // 发送邮件
            EmsMainEngine mainEngine = mainEngineMap.get(myBorrow.getFixedNo());
            if (mainEngine != null) {
                sendApprovalEmail(myBorrow, mainEngine, userLoginVO, request.getRejectReason(), isApproval);
            }
        }
    }
    
    /**
     * 批量处理借用拒绝的业务逻辑
     */
    private void processBorrowRejectionBatch(List<EmsMyBorrow> myBorrowList, WorkOrderSampleBatchApprovalRequest request, 
                                           UserLoginVO userLoginVO) {
        // 批量查询主引擎数据
        Set<String> fixedNos = myBorrowList.stream().map(EmsMyBorrow::getFixedNo).collect(Collectors.toSet());
        Map<String, EmsMainEngine> mainEngineMap = getMainEngineMap(fixedNos);
        
        for (EmsMyBorrow myBorrow : myBorrowList) {
            // 记录审批日志
            saveApprovalLog(myBorrow, userLoginVO, "拒绝", 
                          request.getRejectReason() != null ? request.getRejectReason() : "样品管理员拒绝审批", 
                          "样品分配(工单)");
            
            // 恢复样品数量和状态 - 这里已经包含了库存恢复逻辑，不需要额外调用updateInventoryForRejection
            sampleStatusUtils.updateSampleQuantityAndStatus(myBorrow.getBorrowNum(), 
                                                          myBorrow.getFixedNo(), 
                                                          SampleStatusUtils.OperationType.SCRAP_RESTORE.getCode(), 2);
            
            // 注释掉重复的库存更新，避免双重恢复库存
            // updateInventoryForRejection(myBorrow);
            
            // 发送邮件
            EmsMainEngine mainEngine = mainEngineMap.get(myBorrow.getFixedNo());
            if (mainEngine != null) {
                sendApprovalEmail(myBorrow, mainEngine, userLoginVO, request.getRejectReason(), false);
            }
        }
    }
    
    /**
     * 批量获取主引擎数据映射
     */
    private Map<String, EmsMainEngine> getMainEngineMap(Set<String> fixedNos) {
        LambdaQueryWrapper<EmsMainEngine> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(EmsMainEngine::getFixedNo, fixedNos)
                   .select(EmsMainEngine::getFixedNo, EmsMainEngine::getModelName, EmsMainEngine::getPredictDate,
                          EmsMainEngine::getCategory, EmsMainEngine::getBigCategory, EmsMainEngine::getRemark,
                          EmsMainEngine::getUserName, EmsMainEngine::getUserId, EmsMainEngine::getScrapNum,
                          EmsMainEngine::getInventoryNum);
        
        List<EmsMainEngine> mainEngines = emsMainEngineService.list(queryWrapper);
        return mainEngines.stream().collect(Collectors.toMap(EmsMainEngine::getFixedNo, engine -> engine));
    }
    
    /**
     * 保存审批日志
     */
    private void saveApprovalLog(EmsMyBorrow myBorrow, UserLoginVO userLoginVO, String result, 
                               String reason, String desc) {
        EmsLogRecord logRecord = new EmsLogRecord();
        logRecord.setFixedNo(myBorrow.getFixedNo());
        logRecord.setDesc(desc);
        logRecord.setRole(userLoginVO.getNotes());
        logRecord.setOperator(userLoginVO.getUserName());
        logRecord.setType("审批(工单)");
        logRecord.setResult(result);
        logRecord.setReason(reason != null ? reason : "");
        logRecord.setTime(LocalDateTime.now());
        emsLogRecordService.save(logRecord);
    }
    
    /**
     * 发送审批邮件
     */
    private void sendApprovalEmail(EmsMyBorrow myBorrow, EmsMainEngine mainEngine, UserLoginVO userLoginVO, 
                                 String rejectReason, boolean isApproval) {
        // 构建邮件数据
        ArrayList<HashMap<String, String>> tableDatas = new ArrayList<>();
        HashMap<String, String> tableDataMap = new HashMap<>();
        tableDataMap.put("id", myBorrow.getFixedNo());
        tableDataMap.put("name", mainEngine.getModelName());
        tableDataMap.put("predictDate", String.valueOf(mainEngine.getPredictDate()));
        tableDataMap.put("big_category", mainEngine.getBigCategory());
        tableDataMap.put("category", mainEngine.getCategory());
        tableDataMap.put("number", String.valueOf(myBorrow.getBorrowNum()));
        tableDataMap.put("desc", mainEngine.getRemark());
        if (!isApproval) {
            tableDataMap.put("rejectReason", rejectReason);
        }
        tableDatas.add(tableDataMap);
        
        // 创建邮件队列记录
        EmsMailQueue emsMailQueue = new EmsMailQueue();
        emsMailQueue.setFrom(userLoginVO.getEmail());
        emsMailQueue.setTableData(tableDatas.toString());
        
        // 获取收件人邮箱
        String recipientEmail = Optional.ofNullable(usersService.getLoginUserInfo(myBorrow.getUserId()))
                .map(UserLoginVO::getEmail)
                .orElse(null);
        ArrayList<String> emailList = new ArrayList<>();
        emailList.add(recipientEmail);
        emsMailQueue.setTo(String.valueOf(emailList));
        if (isApproval) {
            emsMailQueue.setType(MailEnum.APPLY.getValue());
            emsMailQueue.setMainBody(mailTemplate.getReplyApproveBorrowApplyFromSample(myBorrow.getUserName()));
            emsMailQueue.setSubject(MailTemplate.SUBJECT_BORROW_APPLY_APPROVE_FROM_SAMPLE + userLoginVO.getUserName());
        } else {
            emsMailQueue.setType(MailEnum.REJECT.getValue());
            emsMailQueue.setMainBody(mailTemplate.getReplyRejectBorrowApplyFromSample(mainEngine.getUserName()));
            emsMailQueue.setSubject(MailTemplate.SUBJECT_BORROW_APPLY_REJECT_FROM_SAMPLE + userLoginVO.getUserName());
        }
        
        emsMailQueueService.save(emsMailQueue);
    }
    
    /**
     * 更新库存数量（拒绝时恢复库存）
     */
    private void updateInventoryForRejection(EmsMyBorrow myBorrow) {
        String fixedNo = myBorrow.getFixedNo();
        Integer borrowNum = myBorrow.getBorrowNum();
        
        EmsMainEngine mainEngine = emsMainEngineService.getOne(
            new LambdaQueryWrapper<EmsMainEngine>()
                .eq(EmsMainEngine::getFixedNo, fixedNo)
        );
        
        if (mainEngine != null && borrowNum != null) {
            Integer currentScrapNum = mainEngine.getScrapNum() != null ? mainEngine.getScrapNum() : 0;
            Integer currentInventoryNum = mainEngine.getInventoryNum() != null ? mainEngine.getInventoryNum() : 0;
            
            mainEngine.setScrapNum(Math.max(0, currentScrapNum - borrowNum));
            mainEngine.setInventoryNum(currentInventoryNum + borrowNum);
            mainEngine.setUpdateTime(LocalDateTime.now());
            emsMainEngineService.updateById(mainEngine);
        }
    }
    
    /**
     * 批量触发状态同步检查
     */
    private void triggerStatusSyncBatch(List<String> requestIds, Integer status) {
        for (String requestId : requestIds) {
            workOrderStatusSyncService.onRequestStatusChange(requestId, status);
        }
    }

    /**
     * 清理拒绝的申请状态缓存
     */
    private void cleanupRejectedRequestsFromRedis(List<String> requestIds) {
        for (String requestId : requestIds) {
            try {
                // 1. 获取申请对应的详情ID
                String mappingKey = RedisKeyEnum.REQUEST_DETAIL_MAPPING.getKey(requestId);
                Object detailId = redisTemplate.opsForValue().get(mappingKey);
                
                if (detailId != null) {
                    String detailIdStr = detailId.toString();
                    
                    // 2. 从详情的审批状态Hash中删除这个申请
                    String approvalKey = RedisKeyEnum.DETAIL_APPROVAL_STATUS.getKey(detailIdStr);
                    redisTemplate.opsForHash().delete(approvalKey, requestId);
                    
                    log.info("从详情审批状态缓存中删除申请: detailId={}, requestId={}", detailIdStr, requestId);
                }
                
                // 3. 删除申请到详情的映射
                redisTemplate.delete(mappingKey);
                
                // 4. 清理旧的审批状态缓存（如果存在）
                String oldRedisKey = RedisKeyEnum.WORKER_ORDER_APPROVAL_PREFIX.getValue() + requestId;
                redisTemplate.delete(oldRedisKey);
                
                log.info("清理申请Redis缓存完成: requestId={}", requestId);
                
            } catch (Exception e) {
                log.error("清理申请Redis缓存失败: requestId={}, 错误: {}", requestId, e.getMessage(), e);
                // 不抛出异常，避免影响主流程
            }
        }
    }


}




